<?php

namespace app\common\service;

use app\data\util\HttpUtil;
use app\order\model\SkuWeightSize;
use app\order\model\SkuWeight;
use app\common\service\ConstantOrderService;
use app\order\logic\OrderShipLogic;
use app\order\logic\OrderWhLogic;
use think\facade\Db;

class ShunfengApiService
{
    protected $token = null;
    protected $appkey = null;
    protected $appsecret = null;
    protected $url = null;
    //物流产品编码
    protected $channelCode = null;
    protected $maxChannelCode = null;

    // 接口权限
    // 4.1商品创建/更新；
    // 5.3入库查询；
    // 6.1出库创建；
    // 6.2出库查询；
    // 6.3出库取消；
    // 6.4出库状态回传；
    // 8.1库存查询；

    public function __construct()
    {
        $this->appkey = Config('Logisticskey.SF.appkey');
        //正式环境url
        $this->url = Config('Logisticskey.SF.url');
        $this->appsecret = Config('Logisticskey.SF.appsecret');
        //小于448g
        $this->channelCode      = Config('Logisticskey.SF.channelCode');
        //大于448g
        $this->maxChannelCode   = Config('Logisticskey.SF.maxChannelCode');

    }

    /**
     * 创建出库单(顺丰出境)
     * @param $order //订单信息
     * @return true
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function createOutBoundOrder($order)
    {
        htmlLog(['data'=>$order],OPERATE_LOG . date('Ym') . '/createOutBoundOrder/' . date('Ymd') . '.txt');
        $return    = [
            'order_id'      => $order['order_id'],
            'shop_id'       => $order['shop_id'],
            'warehouse_id'  => $order['warehouse_id'],
            'data'          => '',
            'return0'       => '',
            'return1'       => '',
        ];
        $orderData  =  $OrderDetail = [];

        //sku信息组装  2024-05-10 查看是否拆分sku
        $exist_split_sku = Db::name('order_split_ship')->where(['order_id'=>$order['order_id']])->find();

        if($exist_split_sku){
            $skuInfos   = $order['skuinfo'];
            $skuInfos   = explode(',',$skuInfos);
        }else{
            $skuInfos   = Db::name('order_info')->where('order_id', $order['order_id'])->column('seller_sku');
        }


        foreach($skuInfos as $v){
            if($exist_split_sku){
                $orderDetail_arr[] = get_seller_sku_change($v);
            }else{
                $orderDetail_arr[] = get_seller_sku($v);
            }
        }



        if(!$orderDetail_arr)  return true;

        //数组整合
        foreach($orderDetail_arr as $v){
                if(isset($v[0]) && is_array($v[0])){
                    foreach($v as $value){
                        $OrderDetail[] = $value;
                    }
                }else{
                        $OrderDetail[] = $v;
            }
        }

        $OrderDetail  = self::getQtyOrdered($OrderDetail);
        $lineNos      = [];
        $randomNumber = random_int(10, 99);
        $OrderDetail  = array_map(function($vin) use (&$lineNos,$randomNumber) {
            // 新的 lineNo 值
            $newLineNo = $vin['lineNo'];

            // 如果 lineNo 已经存在，增加随机数确保唯一性
            while (in_array($newLineNo, $lineNos)) {
                $newLineNo += $randomNumber;
            }

            $lineNos[] = $newLineNo; // 将唯一的 lineNo 存储在数组中

            // 更新 lineNo 和转换 sku
            $vin['lineNo'] = $newLineNo;

            if (!empty($vin['sku'])) {
                $vin['sku'] = strtoupper($vin['sku']);
            }

            return $vin;
        }, $OrderDetail);


        //数据组装;
        $orderData                  = self::buildJsonData($order);
        $orderData['details']       = $OrderDetail;
        //update 2024-02-22 发货总重量判断;
       /* $totalWeight = self::getTotalWeight($OrderDetail);
        if ($totalWeight > 448 && $order['shipping_type'] != 'TIKTOK') {
            $orderData["channelCode"] = 'US_USPS_P';
        }*/

        //update 2024-02-21 顺丰官方面单发货模式入参修改;
        //是否是强制发货
        if ($order['shipping_type'] == 'TIKTOK' && $order['type'] == 2) {
            //新增 跟踪号跟面单不能为空
            if (empty($order['tracking_number']) || empty($order['shipping_documents'])) {
                $return['code'] = 2; //面单跟踪号问题
                $return['msg'] = "发货失败！面单跟踪号等数据未同步，请等待五分钟";
                self::doInsertOrderShipLog($return,$order);
                return true;
            }
            $orderData["channelCode"]  = 'SELF_PICKUP_EXPRESS'; //物流产品编码，使用'快递自提'时传'SELF_PICKUP_EXPRESS'
            $orderData["deliveryNo"]   = $order['tracking_number']; //物流单号
            $orderData["labelUrl"]     = $order['shipping_documents'];//官方面单地址
        }

        // if ($order['modifystatus'] == "hidden")  self::handleUpdateOrder($order=[]);  //手动修改订单信息后发货  //后续加功能  2024-03-29
            $url      = $this->url .  Config('Logisticskey.SF.insert_order_path');
            htmlLog(['url'=>$url,'params'=>$orderData,'order_id'=>$order['order_id']],OPERATE_LOG . date('Ym') . '/createOutBoundOrder/' . date('Ymd') . '.txt');
            $response = HttpUtil::postUrlSF($url, $orderData);
            $result   = json_decode($response, true);
            htmlLog(['response'=>$result,'order_id'=>$order['order_id']],OPERATE_LOG . date('Ym') . '/createOutBoundOrder/' . date('Ymd') . '.txt');
            //记录日志
            if (!empty($result) && $result['code'] == 0) {
                self::handleSuccessShipping($response,$order,$orderData);
            } else {
                self::handleFailedShipping($order, $response,$return);
            }
        return true;
    }

    public function createOutBoundOrderWh($order)
    {

        $return = [
            'order_id' => $order['order_id'],
            'shop_id'  => $order['shop_id'],
            'data'     => '',
            'return0'  => '',
            'return1'  => '',
        ];

        if(!$order['skuinfo'])    return true;
        $orderinfo = explode(',', $order['skuinfo']);
        foreach ($orderinfo as  $v) {
            $orderDetail_arr[] = get_seller_sku($v);
        }

        if (!$orderDetail_arr){
            $return['code'] = 2; //SKU问题
            $return['msg'] = "发货失败！SKU数据未同步，请等待五分钟";
            self::insertOrderWhLogSf($return,$order);
            return  true;
        }



        //数组整合
        foreach($orderDetail_arr as $v){
            if(isset($v[0]) && is_array($v[0])){
                foreach($v as $value){
                    $OrderDetail[] = $value;
                }
            }else{
                $OrderDetail[] = $v;
            }
        }

        $OrderDetail  = self::getQtyOrdered($OrderDetail);
        $lineNos      = [];
        $randomNumber = random_int(10, 99);
        $OrderDetail  = array_map(function($vin) use (&$lineNos,$randomNumber) {
            // 新的 lineNo 值
            $newLineNo = $vin['lineNo'];

            // 如果 lineNo 已经存在，增加随机数确保唯一性
            while (in_array($newLineNo, $lineNos)) {
                $newLineNo += $randomNumber;
            }

            $lineNos[] = $newLineNo; // 将唯一的 lineNo 存储在数组中

            // 更新 lineNo 和转换 sku
            $vin['lineNo'] = $newLineNo;

            if (!empty($vin['sku'])) {
                $vin['sku'] = strtoupper($vin['sku']);
            }

            return $vin;
        }, $OrderDetail);

        //数据组装;
        $orderData                  = self::buildJsonData($order);
        $orderData['details']       = $OrderDetail;
        $url      = $this->url .  Config('Logisticskey.SF.insert_order_path');
        htmlLog(['url'=>$url,'order_param'=>$order,'params'=>$orderData,'order_id'=>$order['order_id']],OPERATE_LOG . date('Ym') . '/createOutBoundOrderWh/' . date('Ymd') . '.txt');
        $response = HttpUtil::postUrlSF($url, $orderData);
        $result   = json_decode($response, true);
        htmlLog(['response'=>$result,'order_id'=>$order['order_id']],OPERATE_LOG . date('Ym') . '/createOutBoundOrderWh/' . date('Ymd') . '.txt');
        if($result && $result['code'] == 0){
            self::handleSuccessWhShipping($response,$order);
        }else{
            self::handleFailedWhShipping($order, $response,$return);
        }
        return true;
    }

    /**
     * @desc 获取发货总重量;
     * @author xx
     * @date 2024-02-22
     */
    public function getTotalWeight($OrderDetail3)
    {
        if (!$OrderDetail3) {
            return  0;
        }
        $skus = array_column($OrderDetail3, 'sku');
        $weightInfo =  (new SkuWeight())->where([
            'new_sku' => $skus
        ])->field('UPPER(new_sku) as new_sku,weight')->select()->toArray();
        $weightInfoMap = array_column($weightInfo, null, 'new_sku');
        $info          = array_column($OrderDetail3, null, 'sku');
        $totalWeight   = 0;
        if (!$info) {
            return  0;
        }
        foreach ($info as $v) {
            $weightValues       = $weightInfoMap[$v['sku']] ?? [];
            $weight             = isset($weightValues['weight']) && $weightValues['weight'] ? intval($weightValues['weight'] * $v['qtyOrdered']) : 0;
            $totalWeight        += $weight;
        }
        return $totalWeight;
    }


    /**
     * @desc 数据统计
     * @date 2024-02-22
     */
    public function getQtyOrdered($info)
    {
        $outputArray = [];
        foreach ($info as $item) {
            $sku = $item['sku'];
            if (isset($outputArray[$sku])) {
                $outputArray[$sku]['qtyOrdered'] += $item['qtyOrdered'];
            } else {
                $outputArray[$sku] = $item;
            }
        }
        return array_values($outputArray);
    }




    /**
     * @desc  构建 JsonData返货参数处理
     * @date  2024-03-30
     * @author luckyXiong
     */
    public function buildJsonData($order=[]){
        $orderData                  = [];
        $orderData['bonded']        = false; //是否保税
        $orderData['refNo1']        = $order['order_id']; //跟踪号
        $orderData['refNo2']        = $order['order_id']; //客户订单号
        $orderData['channelCode']   = $this->channelCode; //物流产品代码，具体请咨询
        $orderData['warehouseCode'] = 'USLA-S1'; //仓库编码
        $orderData['customerCode']  = 'A0805'; //客户编码
        $orderData['orderType']     = 'CM'; //订单类型,CM-标准出库，默认为CM，OB-标准出库toB，RT-不良品出库，PS-预售
        $orderData['consigneeName'] = $order['name']; //收货人名称
        //收货人手机号处理
        $phone_1                    = '';
        if (!empty($order['phone_number'])) {
            $phone_1 = explode(')', $order['phone_number']);
            $phone_1 = $phone_1[1] ?? $phone_1[0];
        }
        $orderData['consigneeMobile']   = !empty($phone_1) ? $phone_1 : '';
        $orderData['consigneeCountry']  = 'US'; //收货人国家代码
        $orderData['consigneeZip']      = $order['postal_code']; //收货人邮编
        $orderData['consigneeProvince'] = $order['state']; //收货人省份
        $orderData['consigneeCity']     = $order['city']; //收货人城市
        $orderData['consigneeAddress1'] = $order['address_detail']; //收货人地址
        return  $orderData;
    }

    /**
     * @desc  发货失败
     * @date  2024-03-30
     * @author luckyXiong
     */
    public function doInsertOrderShipLog($return=[],$order=[]){
        $updateShip['status'] = 2;
        $updateShip['time']   = time();
        $updateShip['msg']    = $return['msg'];
        $exist_ship           = Db::name('order_ship')->where('order_id', $order['order_id'])->find();
        if($exist_ship){
            Db::name('order_ship')->where('order_id', $order['order_id'])->update($updateShip);
        }else{
            Db::name('order_ship')->insert([
                'order_id'    =>$order['order_id'],
                'shop_id'     =>$order['shop_id'],
                'warehouse_id'=>$order['warehouse_id'],
                'status'      =>2,
                'time'        =>time(),
                'msg'         =>$return['msg'],
                'type'        =>$order['type'],
            ]);
        }
        OrderShipLogic::insertOrderShipLog($return);
    }




    /**
     * @desc 处理发货成功的情况
     * @date  2024-03-30
     * @author luckyXiong
     */
    private function handleSuccessShipping($response=[],$order=[],$orderData=[])
    {
        $result            = json_decode($response, true);
        $return['code']    = 3;
        $return['msg']     = $order['shipping_type'] == 'TIKTOK' ?  "操作成功" : "等待回传物流单号";
        $return['return0'] = $response;
        $return['order_id']    = $order['order_id']??'';
        $return['shop_id']     = $order['shop_id']??'';
        $return['data']    = '';
        $tracking_number   = '';
        //有跟踪号代表发货了
        $msg                            = '顺丰自发货，已发货';
        $status                         = 3;

        if($order['type'] == 2){ //顺丰走官方面单发货，已返回真实运单
            $return['msg']         = "强制顺丰发货成功，已回传面单，不继续进行后续操作";
            $return['return0']     = json_encode($orderData);
            $msg                   = "发货成功，顺丰走官方面单发货,无需后续刷运单号";
            $status                = 5;
            $tracking_number       = Db::name('order')->where('order_id',$order['order_id'])->value('tracking_number');
        }


        $exist_ship = Db::name('order_ship')->where('order_id', $order['order_id'])->find();
        if(!$exist_ship){
            Db::name('order_ship')->where('order_id', $order['order_id'])->insert([
                    'order_id'        =>$order['order_id'],
                    'shop_id'         =>$order['shop_id'],
                    'warehouse_id'    =>$order['warehouse_id'],
                    'status'          =>$status,
                    'time'            =>time(),
                    'tracking_number' =>$tracking_number,
                    'msg'             =>$msg,
                    'type'            =>$order['type']
                ]
            );
        }else{
            Db::name('order_ship')->where('order_id', $order['order_id'])->update([
                    'warehouse_id'     =>$order['warehouse_id'],
                    'status'           =>$status,
                    'time'             =>time(),
                    'tracking_number'  =>$tracking_number,
                    'msg'              =>$msg,
                ]
            );
        }



        Db::name('order')->where('order_id', $order['order_id'])->update([
            'send_status'=>1
        ]);


        //更新仓库ID
        Db::name('order_split_ship')
            ->where([
                'order_id'  =>$order['order_id'],
                'seller_sku'=>$order['skuinfo'],
            ])->update(
                [
                    'warehouse_id' =>$order['warehouse_id'],
                    'status'       =>1,
                    'update_time'  =>date("Y-m-d H:i:s", time()),
                ]);
        OrderShipLogic::insertOrderShipLog($return);
    }

    /**
     * @desc 处理发货失败的情况
     * @date  2024-03-30
     * @author luckyXiong
     */
    private function handleFailedShipping($order=[], $response=[],$return=[])
    {
        $result            = json_decode($response, true);
        $return['code']    = 2;
        $return['msg']     = "错误：" . $result['msg'];
        $return['return0'] = $response;

        $updateShip['status'] = 2;
        $updateShip['time']   = time();
        $updateShip['msg']    = "错误：" . $result['msg'];
        $updateShip['warehouse_id'] = $order['warehouse_id'];

        $exist_ship = Db::name('order_ship')->where('order_id',$order['order_id'])->find();
        if(!$exist_ship){
            Db::name('order_ship')->insert([
                'order_id'    =>$order['order_id'],
                'shop_id'     =>$order['shop_id'],
                'warehouse_id'=>$order['warehouse_id'],
                'status'      =>2,
                'time'        =>time(),
                'msg'         =>$response,
                'type'        =>$order['type'],
            ]);
        }else{
            //异常重发页面失败了才改为已处理
            if($order['fail_status']==6){
                $updateShip['status'] = 5; //失败改为已处理
            }
            Db::name('order_ship')->where('order_id', $order['order_id'])->update($updateShip);
        }

        Db::name('order')->where('order_id', $order['order_id'])->update([
            'send_status'=>2
        ]);


        //更新仓库ID
        Db::name('order_split_ship')
            ->where([
                'order_id'  =>$order['order_id'],
                'seller_sku'=>$order['skuinfo'],

            ])
            ->update(
                [
                    'warehouse_id'   =>$order['warehouse_id'],
                    'msg'            =>$result['msg'],
                    'update_time'    =>date("Y-m-d H:i:s", time()),
                ]);

        OrderShipLogic::insertOrderShipLog($return);
    }


    /**
     * @desc 处理发货成功的情况
     * @date  2024-03-30
     * @author luckyXiong
     */
    private function handleSuccessWhShipping($response=[],$order=[])
    {

        $result            = json_decode($response, true);
        $number            = $result['data']??'';
        $return['code']    = 3;
        $return['msg']     = "待顺丰回传物流单号";
        $return['return0'] = $response;
        $return['data']    = $number;
        $return['warehouse_id']    = $order['warehouse_id'];

        $update['tracking_beforehand'] = 3;
        $update['warehouse_id']        = $order['warehouse_id'];
        $update['updatetime']          = time();
        $update['msg']                 = "待顺丰回传物流单号";

        Db::name('orderwh')->where('order_id', $order['order_id'])->update($update);
        OrderWhLogic::insertOrderWhLog($return);
    }

    /**
     * @desc 处理发货失败的情况
     * @date  2024-03-30
     * @author luckyXiong
     */
    private function handleFailedWhShipping($order=[], $response=[],$return=[])
    {
        $result            = json_decode($response, true);
        $return['code']    = 2;
        $return['msg']     = "错误：" . $result['msg'];
        $return['return0'] = $response;

        $update['tracking_beforehand']  = 2;
        $update['warehouse_id']  = $order['warehouse_id'];
        $update['updatetime']    = time();
        $update['msg']           = "错误：" . $result['msg'];
        Db::name('orderwh')->where('order_id', $order['order_id'])->update($update);
        OrderWhLogic::insertOrderWhLog($return);
    }



    /**
     * @desc 手动修改订单发货处理
     * @date  2024-03-30
     * @author luckyXiong
     */
    public function handleUpdateOrder($order = []){
        $orderData = [];
        if (!empty($order['skuinfo'])) {
            $skuinfos = explode(',', $order['skuinfo']);
            $OrderDetail3 = array();
            foreach ($skuinfos as $ksku => $vsku) {
                $test = array();
                $test["lineNo"] = (int)$ksku + 1;
                $test["sku"] = $vsku;
                if (!empty($test["sku"])) {
                    //变成大写
                    $test["sku"] = strtoupper($test["sku"]);
                }
                $test["qtyOrdered"] = 1;
                $OrderDetail3[] = $test;
            }
            $orderData['details'] = $OrderDetail3;
        }
        return $orderData;
    }


    /**
     * @desc 网红订单顺丰日志记录
     * @date  2024-03-30
     * @author luckyXiong
     */
     public function insertOrderWhLogSf($return=[],$order=[]){
         $update['status']       = 2;
         $update['updatetime']   = time();
         $update['msg']          = $return['msg'];
         Db::name('orderwh')->where('order_id', $order['order_id'])->update($update);
         OrderWhLogic::insertOrderWhLog($return);
    }



    /**
     * @desc   顺丰物流单号获取后推送到TIK
     * @Date   2024-4-15
     * @Author  luckyXiong
     */
    public function order_tracking_number_sf_back($info=[]){
        if(!$info)   return  true;
        $field       = 'id,app_key,cipher,app_secret,access_token';
        $account     = Db::name('shops')->where('id',$info['shop_id'])->field($field)->find();
        $base_url    = Config('Logisticskey.TIKTOK.basic_url');
        $path        = Config('Logisticskey.TIKTOK.orders_fulfillment_path');
        $delivery_option_id  = $info['shipping_provider_id'];
        $path = $path . $info['order_id'] . '/packages';
        $sign = $account['app_secret'] . '' . $path . 'app_key' . $account['app_key'] . 'shop_cipher' . $account['cipher'] . 'timestamp' . time() . '{"shipping_provider_id":"' . $delivery_option_id . '","tracking_number":"' . $info['tracking_number'] . '"}' . $account['app_secret'];
        $sign = hash_hmac('sha256', $sign, $account['app_secret']);
        $url = $base_url . $path . "?app_key=" . $account['app_key'] . "&shop_cipher=" . $account['cipher'] . "&sign=" . $sign . "&timestamp=" . time();
        htmlLog(['shipping_provider_id'=>$delivery_option_id,'tracking_number'=>$info['tracking_number']],OPERATE_LOG . date('Ym') . '/order_tracking_number_tik_back/' . date('Ymd') . '.txt');
        return HttpUtil::tikPostUrl($url, ['shipping_provider_id'=>$delivery_option_id,'tracking_number'=>$info['tracking_number']], $account['access_token']);
    }




}
